在寫程式當中,因應需求需要運用到多個三方套件,為了讓程式碼來達到開放封閉原則
我們經常會使用到 interface
interface 的運用可以提高高內聚,低耦合(high cohesion、low coupling)
在其他語言上也有 interface 的觀念,在 golang 當中還是略有些不同
在 oop 當中的 interface 比較像是公約、規則,
oop implement interface 過程當中會思考物件行為是否符合條件並實作細節
在 golang 當中 interface 是一組 method 簽名,當類型有 implement interface mthdos時,即表示擁有有這項行為能力
package main
import "fmt"
func main() {
p := Phone{}
c := Camera{}
computer := Computer{}
computer.Working(p)
computer.Working(c)
}
type Usb interface {
Start()
Stop()
}
type Phone struct {
}
func (p Phone) Start() {
fmt.Println("手機開始工作")
}
func (p Phone) Stop() {
fmt.Println("手機開始工作")
}
type Camera struct {
}
func (c Camera) Start() {
fmt.Println("相機開始工作")
}
func (c Camera) Stop() {
fmt.Println("相機開始工作")
}
type Computer struct{}
func (c Computer) Working(u Usb) {
u.Start()
u.Stop()
}
不包含任何的方法,所有類型的值都實現空接口,因此空接口可以存儲任意類型的數值
可以看出 fmt package 很多方法允許接收任意類型的數值
package main
import "fmt"
func main() {
var a A = Phone{"iphone 8"}
var a1 A = Person{"jhon", 20}
var a2 A = 123
var a3 A = "test"
fmt.Println(a)
fmt.Println(a1)
fmt.Println(a2)
fmt.Println(a3)
}
//空街口,代表可以是任意的值
type A interface {
}
type Phone struct {
Type string
}
type Person struct {
name string
age int
}
可以藉由類型斷言來判斷 interface 原先的類型為何
藉由 fmt.Println() 為例,可以查看出 printArg method 也是用 Type Assertions 方式來推算出類型
package main
import (
"fmt"
"math"
)
func main() {
var t = Triangle{3, 4, 5}
fmt.Println(t.perimeter())
fmt.Println(t.area())
fmt.Println(t.a, t.b, t.c)
var c = Circle{4}
fmt.Println(c.perimeter())
fmt.Println(c.area())
fmt.Println(c.radius)
assertType(t)
assertType(c)
assertType2(t)
assertType2(c)
}
func assertType(s Shape) {
if t, ok := s.(Triangle); ok {
fmt.Printf("類行為三角形 三邊長為 %f,%f,%f\n", t.a, t.b, t.c)
} else if t, ok := s.(Circle); ok {
fmt.Printf("類行為圓形類型 %+v", t)
} else {
fmt.Printf("其他類型 %+v", s)
}
}
func assertType2(s Shape) {
switch t := s.(type) {
case Shape:
fmt.Println("圓形", t)
case Triangle:
fmt.Println("三角形", t)
default:
fmt.Println("其他類型 ", t)
}
}
type Shape interface {
perimeter() float64
area() float64
}
type Triangle struct {
a, b, c float64
}
func (t Triangle) perimeter() float64 {
return t.a + t.b + t.c
}
func (t Triangle) area() float64 {
p := t.perimeter() / 2
s := math.Sqrt(p * (p - t.a) * (p - t.b) * (p - t.c))
return s
}
type Circle struct {
radius float64
}
func (c Circle) perimeter() float64 {
return c.radius * 2
}
func (c Circle) area() float64 {
return math.Pow(c.radius, 2) * math.Pi
}